

namespace chatroom{
    // 1  brpc服务端
    class FriendServiceImp : public chatroom::FriendService{
    public:
        FriendServiceImp(){}
        ~FriendServiceImp(){}
        //获取好友列表
         virtual void GetFriendList(::google::protobuf::RpcController* controller,
                       const ::chatroom::GetFriendListReq* request,
                       ::chatroom::GetFriendListRsp* response,
                       ::google::protobuf::Closure* done)
                       {
                            brpc::ClosureGuard guard(done);
                            //定义错误回调
                            auto errmsg_response = [this,response](const std::string& rid,const std::string& errmsg) ->void{
                                            response->set_success(false);
                                            response->set_request_id(rid);
                                            request->set_errmsg(errmsg);
                                            return;
                            }
                            std::string rid = request->request_id();
                            //1. 提取请求中的关键要素：用户ID
                            std::string user_id = request->user_id();
                            //2. 从数据库中查询获取用户的好友ID
                            auto friend_lists = _sql_relation->Get_friendID(user_id);
                            //3. 从用户子服务批量获取用户信息 需要调用用户子服务
                            std::unordered_set<std::string> set;
                            for(auto& id : friend_lists)
                            {
                                set.insert(id);
                            }
                            std::map<std::string,UserInfo> Map1;
                            bool ret = _GetUserInfo(rid,set,Map1);
                            if(!ret)
                            {
                                Logger_ERROR("获取好友信息失败");
                                return errmsg_response(rid,"获取好友信息失败");
                            }
                            //4. 组织响应
                            for(auto& mapping : Map1)
                            {
                                response->add_friend_list()->CopyFrom(mapping.second);
                            }
                            response->set_success(true);
                            resopnse->set_request_id(request->request_id());
                       }
        //删除好友
        virtual void FriendRemove(::google::protobuf::RpcController* controller,
                            const ::chatroom::FriendRemoveReq* request,
                            ::chatroom::FriendRemoveRsp* response,
                            ::google::protobuf::Closure* done)
                            {
                                
                                brpc::ClosureGuard guard(done);
                                //定义错误回调
                                auto errmsg_response = [this,response](const std::string& rid,const std::string& errmsg) ->void{
                                                response->set_success(false);
                                                response->set_request_id(rid);
                                                request->set_errmsg(errmsg);
                                                return;
                                }
                                std::string rid = request->request_id();
                                //1. 提取关键要素：当前用户ID，要删除的好友ID
                                std::string user_id = request->user_id();
                                std::string peer_id = request->peer_id();
                                //2. 从好友关系表中删除好友关系信息
                                bool ret = _sql_relation->remove(user_id,peer_id);
                                if(!ret)
                                {
                                    Logger_ERROR("{}删除好友失败",user_id);
                                    return errmsg_response(rid,"删除好友失败");
                                }       
                                //3. 从会话信息表中，删除对应的聊天会话 -- 同时删除会话成员表中的成员信息
                                ret = _sql_chat_session->remove(user_id,peer_id);
                                if(!ret)
                                {
                                    Logger_ERROR("{}会话信息删除失败",user_id);
                                    return errmsg_response(rid,"会话信息删除失败");
                                }
                                //4. 组织响应
                                response->success(true);
                                response->request_id(rid);
                            }
        virtual void FriendAdd(::google::protobuf::RpcController* controller,
                            const ::chatroom::FriendAddReq* request,
                            ::chatroom::FriendAddRsp* response,
                            ::google::protobuf::Closure* done)
                            {
                                brpc::ClosureGuard guard(done);
                                //定义错误回调
                                auto errmsg_response = [this,response](const std::string& rid,const std::string& errmsg) ->void{
                                                response->set_success(false);
                                                response->set_request_id(rid);
                                                request->set_errmsg(errmsg);
                                                return;
                                }
                                std::string rid = request->request_id();
                                //1. 提取请求中的关键要素：申请人用户ID； 被申请人用户ID
                                std::string user_id = request->user_id();
                                std::string respondent_id = request->respondent_id();
                                //2. 判断两人是否已经是好友
                                bool ret = _sql_relation->exist(user_id,respondent_id);
                                if(ret)
                                {
                                    Logger_ERROR("{}已经是好友了,无需申请",user_id);
                                    return errmsg_response(rid,"已经是好友了,无需申请");
                                }   
                                //3. 当前是否已经申请过好友
                                ret = _sql_friend_apply->exist(user_id,respondent_id);
                                if(ret)
                                {
                                    Logger_ERROR("{}已经申请过好友了,请等待对方同意",user_id);
                                    return errmsg_response(rid,"已经申请过好友了,请等待对方同意");
                                }
                                //4. 向好友申请表中，新增申请信息
                                std::string eid = uuid();
                                friend_apply friend1(eid,user_id,respondent_id);
                                ret = _sql_friend_apply->insert(friend1);
                                if(!ret)
                                {
                                    Logger_ERROR("新增{}申请信息失败",user_id);
                                    return errmsg_response(rid,"新增申请信息失败");
                                }
                                //返回响应
                                response->set_success(true);
                                response->set_request_id(rid);
                                response->set_notify_event_id(eid);
                            }
        virtual void FriendAddProcess(::google::protobuf::RpcController* controller,
                            const ::chatroom::FriendAddProcessReq* request,
                            ::chatroom::FriendAddProcessRsp* response,
                            ::google::protobuf::Closure* done)
                            {
                                brpc::ClosureGuard guard(done);
                                //定义错误回调
                                auto errmsg_response = [this,response](const std::string& rid,const std::string& errmsg) ->void{
                                                response->set_success(false);
                                                response->set_request_id(rid);
                                                request->set_errmsg(errmsg);
                                                return;
                                }
                                std::string rid = request->request_id();
                                //1. 提取请求中的关键要素：申请人用户ID；被申请人用户ID；处理结果；事件ID
                                std::string notify_event_id = request->notify_event_id();
                                std::string apply_user_id = request->apply_user_id();
                                bool agree = request->agree();
                                std::string user_id = request->user_id();
                                //2. 判断有没有该申请事件
                                bool ret = _sql_friend_apply.exist(apply_user_id,user_id);
                                if(!ret)
                                {
                                    Logger_ERROR("不存在{}该申请事件",user_id);
                                    return errmsg_response(rid,"新增申请信息失败");
                                }
                                //3. 如果有： 可以处理； --- 删除申请事件--事件已经处理完毕
                                ret = _sql_friend_apply->remove(apply_user_id,user_id);
                                if(!ret)
                                {
                                    Logger_ERROR("{}删除申请事件失败",user_id);
                                    return errmsg_response(rid,"删除申请事件失败");
                                }
                                //4. 如果处理结果是同意：向数据库新增好友关系信息；新增单聊会话信息及会话成员
                                if(agree)
                                {
                                   ret = _sql_relation->insert(apply_user_id,user_id);
                                   if(!ret)
                                   {
                                        Logger_ERROR("{}向数据库中新增好友关系失败",user_id);
                                        return errmsg_response(rid,"向数据库中新增好友关系失败");
                                   }
                                   std::string ssid = uuid();
                                   chat_session cs(ssid,"",ChatSessionType::SINGAL);
                                   _sql_chat_session->insert(cs);
                                    ChatSessionMember csm1(ssid,user_id);
                                    ChatSessionMember csm2(ssid,apply_user_id);
                                    _sql_chat_member->insert(csm1);
                                    _sql_chat_member->insert(csm2);
                                }
                                //5. 组织响应
                                response->set_request_id(rid);
                                response->set_success(true);
                                response->set_new_session_id(notify_event_id); 
                            }
        virtual void FriendSearch(::google::protobuf::RpcController* controller,
                            const ::chatroom::FriendSearchReq* request,
                            ::chatroom::FriendSearchRsp* response,
                            ::google::protobuf::Closure* done)
                            {
                                brpc::ClosureGuard guard(done);
                                //定义错误回调
                                auto errmsg_response = [this,response](const std::string& rid,const std::string& errmsg) ->void{
                                                response->set_success(false);
                                                response->set_request_id(rid);
                                                request->set_errmsg(errmsg);
                                                return;
                                }
                                std::string rid = request->request_id();
                                //1. 提取请求中的关键要素：搜索关键字（可能是用户ID，可能是手机号，可能是昵称的一部分）
                                std::string search_key = request->search_key();
                                std::string user_id =  request->user_id();
                                //2. 根据用户ID，获取用户的好友ID列表
                                auto friend_lists = _sql_relation->Get_friendID(user_id);
                                //3. 从ES搜索引擎进行用户信息搜索 --- 过滤掉当前的好友: 包括自己
                                std::unordered_set<std::string> user_id_list;
                                friend_lists.insert(user_id);
                                auto user_list = _es_user->search(search_key,friend_lists);
                                for(auto& user : user_list)
                                {
                                    user_id_list.insert(user.user_id());
                                }
                                
                                //4. 根据获取到的用户ID， 从用户子服务器进行批量用户信息获取
                               std::map<std::string,UserInfo> Map1;
                               bool ret = _GetUserInfo(rid,user_id_list,Map1);
                               if(!ret)
                               {
                                   Logger_ERROR("获取好友信息失败");
                                   return errmsg_response(rid,"获取好友信息失败");
                               }
                                //4. 组织响应
                                for(auto& mapping : Map1)
                                {
                                    response->add_user_info()->CopyFrom(mapping.second);
                                }
                                response->set_success(true);
                                resopnse->set_request_id(request->request_id());
                            }
        virtual void GetChatSessionList(::google::protobuf::RpcController* controller,
                            const ::chatroom::GetChatSessionListReq* request,
                            ::chatroom::GetChatSessionListRsp* response,
                            ::google::protobuf::Closure* done)
                            {
                                brpc::ClosureGuard guard(done);
                                //定义错误回调
                                auto errmsg_response = [this,response](const std::string& rid,const std::string& errmsg) ->void{
                                                response->set_success(false);
                                                response->set_request_id(rid);
                                                request->set_errmsg(errmsg);
                                                return;
                                }
                                std::string rid = request->request_id();
                                //获取聊天会话的作用：一个用户登录成功后，能够展示自己的历史聊天信息
                                //1. 提取请求中的关键要素：当前请求用户ID
                                std::string user_id = request->user_id();
                                //2. 从数据库中查询出用户的单聊会话列表
                                auto friend_lists = _sql_chat_session->singleChatSession(user_id)
                                    //  1. 从单聊会话列表中，取出所有的好友ID，从用户子服务获取用户信息
                                std::unordered_set<std::string> id_list;
                                for(auto& id:friend_lists)
                                {
                                    id_list.insert(id.friend_id);
                                }  
                                std::map<std::string,UserInfo> Map1;
                                bool ret = _GetUserInfo(rid,id_list,Map1);
                                if(!ret)
                                {
                                    Logger_ERROR("获取好友信息失败");
                                    return errmsg_response(rid,"获取好友信息失败");
                                }
                                    //  2. 设置响应会话信息：会话名称就是好友名称；会话头像就是好友头像
                                auto index = response->mutable_chat_session_info_list();
                                for(auto& id : friend_lists)
                                {
                                    MessageInfo msg;
                                    bool ret = _GetrecentMessage(rid,id.session_id,msg);
                                    if(!ret)
                                    {
                                        Logger_ERROR("获取最后一条信息失败");
                                        return errmsg_response(rid,"获取最后一条信息失败");
                                    }
                                    index->set_single_chat_friend_id(id.friend_id)
                                    index->set_chat_session_name(Map1[id.friend].nickname());
                                    index->mutable_prev_message()->CopyFrom(msg);
                                    index->set_avatar(Map1[id.friend].avatar());
                                    index->set_chat_session_id(id.session_id);
                                }
                                    //3. 从数据库中查询出用户的群聊会话列表
                                auto group_session = _sql_chat_session->groupChatSession(user_id);
                                    //4. 根据所有的会话ID，从消息存储子服务获取会话最后一条消息
                                for(auto& group_id : group_session)
                                {
                                    MessageInfo msg;
                                    bool ret = _GetrecentMessage(rid,group_id.session_id,msg);
                                    if(!ret)
                                    {
                                        Logger_ERROR("获取最后一条信息失败");
                                        return errmsg_response(rid,"获取最后一条信息失败");
                                    }
                                    auto info = response->mutable_chat_session_info_list();
                                    info->mutable_prev_message()->CopyFrom(msg);
                                    info->set_chat_session_id(group_id.session_id); 
                                    info->set_chat_session_name(group_id.friend_id);
                                }
                                    //5. 组织响应
                                response->set_success(true);
                                response->set_request_id(rid);
                            }
        virtual void ChatSessionCreate(::google::protobuf::RpcController* controller,
                            const ::chatroom::ChatSessionCreateReq* request,
                            ::chatroom::ChatSessionCreateRsp* response,
                            ::google::protobuf::Closure* done)
                            {
                                brpc::ClosureGuard guard(done);
                                //定义错误回调
                                auto errmsg_response = [this,response](const std::string& rid,const std::string& errmsg) ->void{
                                                response->set_success(false);
                                                response->set_request_id(rid);
                                                request->set_errmsg(errmsg);
                                                return;
                                }
                                std::string rid = request->request_id();
                                //创建会话，其实针对的是用户要创建一个群聊会话
                                //1. 提取请求关键要素：会话名称，会话成员
                                std::string session_name = request->chat_session_name();
                                auto member_id_list =  request->member_id_list();
                                //2. 生成会话ID，向数据库添加会话信息，添加会话成员信息
                                std::string session_id =  uuid();
                                chat_session session1(session_id,session_name,ChatSessionType::GROUP);
                                bool ret = _sql_chat_session->insert(session1);
                                if(!ret)
                                {
                                    Logger_ERROR("向数据库添加会话信息失败{}",session_name);
                                    return errmsg_response(rid,"向数据库添加会话信息会话失败");
                                }
                                std::vector<ChatSessionMember> CSM;
                                for(auto& id: member_id_list)
                                {
                                    ChatSessionMember member(session_id,id);
                                    CSM.push_back(member);
                                }
                                ret = _sql_chat_member->multi_append(CSM);
                                if(!ret)
                                {
                                    Logger_ERROR("添加会话成员信息失败{}",session_name);
                                    return errmsg_response(rid,"添加会话成员信息失败");
                                }
                                //3. 组织响应---组织会话信息
                                response->set_success(true);
                                response->set_request_id(rid);
                                auto session_info = response->mutable_chat_session_info();
                                session_info->set_chat_session_id(session_id);
                                session_info->set_chat_session_name(session_name);
                            }
        virtual void GetChatSessionMember(::google::protobuf::RpcController* controller,
                            const ::chatroom::GetChatSessionMemberReq* request,
                            ::chatroom::GetChatSessionMemberRsp* response,
                            ::google::protobuf::Closure* done)
                            {
                                brpc::ClosureGuard guard(done);
                                //定义错误回调
                                auto errmsg_response = [this,response](const std::string& rid,const std::string& errmsg) ->void{
                                                response->set_success(false);
                                                response->set_request_id(rid);
                                                request->set_errmsg(errmsg);
                                                return;
                                }
                                std::string rid = request->request_id();
                                //用于用户查看群聊成员信息的时候：进行成员信息展示
                                //1. 提取关键要素：聊天会话ID
                                std::string session_id = request->chat_session_id();
                                //2. 从数据库获取会话成员ID列表
                                std::vector<string> id_list = _sql_chat_member->get_all(session_id);
                                //3. 从用户子服务批量获取用户信息
                                std::map<std::string,UserInfo> Map1;
                                bool ret = _GetUserInfo(rid,id_list,Map1);
                                for(auto& id : id_list)
                                {
                                    response->add_member_info_list()->CopyFrom(Map1[id]);
                                }
                                response->set_success(true);
                                resopnse->set_request_id(request->request_id());
                            }
        virtual void GetPendingFriendEventList(::google::protobuf::RpcController* controller,
                            const ::chatroom::GetPendingFriendEventListReq* request,
                            ::chatroom::GetPendingFriendEventListRsp* response,
                            ::google::protobuf::Closure* done)
                            {
                                brpc::ClosureGuard guard(done);
                                //定义错误回调
                                auto errmsg_response = [this,response](const std::string& rid,const std::string& errmsg) ->void{
                                                response->set_success(false);
                                                response->set_request_id(rid);
                                                request->set_errmsg(errmsg);
                                                return;
                                }
                                std::string rid = request->request_id();
                                //1. 提取关键要素：当前用户ID
                                std::string user_id = request->user_id();
                                //2. 从数据库获取待处理的申请事件信息 --- 申请人用户ID列表
                                auto id_list = _sql_friend_apply->applyUser(user_id);
                                //3. 批量获取申请人用户信息
                                std::map<std::string,UserInfo> Map1;
                                bool ret = _GetUserInfo(rid,id_list,Map1);
                                if(!ret)
                                {
                                    Logger_ERROR("{}获取用户信息失败",rid);
                                    return errmsg_response(rid,"获取用户信息失败");
                                }
                                //4. 组织响应
                                auto event = response->mutable_event();
                                for(auto& id : id_list)
                                {
                                    event->set_event_id(uuid());
                                    event->mutable_sender()->CopyFrom(Map1[id]);
                                }
                                response->set_success(true);
                                resopnse->set_request_id(rid);
                            }

    private:
        bool _GetrecentMessage(const std::string& rid,const std::string& cssid,MessageInfo& msginfo)
        {
            auto channel = _mm_channel->choose(_message_service_name);
            if(!channel)
            {
                Logger_ERROR("不存在提供信息存储子服务的信道{}",_message_service_name);
                return false;
            }
            chatroom::MessageService_Stub stub(channel.get());
            brpc::Controller* cntl = new brpc::Controller();
            chatroom::GetRecentMsgReq req;
            chatroom::GetRecentMsgRsp rsp;
            req.set_request_id(rid);
            req.set_chat_session_id(cssid);
            req.set_msg_count(1);
            //同步调用用户子服务
            stub.GetRecentMsg(cntl,&req,&rsp,nullptr);
            if(cntl->Failed())
            {
                Logger_ERROR("调用消息子服务失败{},{}",rid,cntl->ErrorText());
                delete cntl;
                return false;
            }
            if(rsp.success()==false)
            {
                Logger_ERROR("获取最新一条消息失败,{}",rid);
                delete cntl;
                return false;
            }
            delete cntl;
            if(rsp.msg_list().size()>0)
            {
                msginfo.CopyFrom(rsp.msg_list(0));
                return true;
            }
            return false;
        }

        //调用用户子服务
        bool _GetUserInfo(const std::string& rid,const unordered_set<std::string>& id_list,std::map<string,UserInfo>& map)
        {
            auto channel = _mm_channel->choose(_user_service_name);
            if(!channel)
            {
                Logger_ERROR("不存在提供用户子服务的信道{}",_user_service_name);
                return false;
            }
            chatroom::UserService_Stub stub(channel.get());
            brpc::Controller* cntl = new brpc::Controller();
            chatroom::GetMultiUserInfoReq req;
            chatroom::GetMultiUserInfoRsp rsp;
            req.set_request_id(rid);
            for(auto& id : id_list)
            {
                request->add_user_id(id);
            }
            //同步调用用户子服务
            stub.GetMultiUserInfo(cntl,&req,&rsp,nullptr);
            if(cntl->Failed())
            {
                Logger_ERROR("调用用户子服务失败{},{}",rid,cntl->ErrorText());
                delete cntl;
                return false;
            }
            if(rsp.success()==false)
            {
                Logger_ERROR("批量获取用户子信息失败,{}",rid);
                delete cntl;
                return false;
            }
            delete cnt1;
            for(auto& user : rsp.user_info())
            {
                map[user.first] = user.second;
            }
            return true;
        }
        chat_session_Table::Ptr _sql_chat_session;
        friend_apply_Table::Ptr _sql_friend_apply;
        relationTable::Ptr _sql_relation;
        ServiceManage::Sptr _mm_channel;
        std::string  _user_service_name;
        std::string _message_service_name;
        ESuser::Ptr _es_user;
        ChatSessionMemTable::Ptr _sql_chat_member;
    };
    class FriendServer{
        public:
            using ptr = std::shared_ptr<FriendServer>;
            speechServer(chatroom::ASRClient::ptr& client,std::shared_ptr<brpc::Server>& server,chatroom::Registery::ptr& rclient)
            :_client(client),_server(server),_rclient(rclient){}
            ~FriendServer(){}
            void start(){
                _server->RunUntilAskedToQuit();
            }
        private:
            std::shared_ptr<brpc::Server> _server;
            chatroom::Registery::ptr _rclient;

    };
    class FriendServerBuild{
        public:
            void make_asr_object(std::string& app_id,std::string& api_key,std::string& secret_key)
            {
                _client = std::make_shared<chatroom::ASRClient>(app_id,api_key,secret_key);
            }
            void make_rpc_server(int32_t port,int32_t timeout,int32_t num_threads)
            {
                _server = std::make_shared<brpc::Server>();
                //3 往服务器中添加服务
                FriendServiceImp* speech = new FriendServiceImp(_client);
                int ret = _server->AddService(speech,brpc::ServiceOwnership::SERVER_OWNS_SERVICE);
                if(ret == -1)
                {
                    Logger_ERROR("添加服务失败");
                    abort();
                }
                //4 启动服务器
                brpc::ServerOptions options;
                options.idle_timeout_sec = timeout; //指定超时连接时间，-1表示超时一直在连接着
                options.num_threads = num_threads;//cpu线程数量
                ret = _server->Start(port,&options);
                if(ret == -1)
                {
                    Logger_ERROR("启动服务器失败");
                    abort();
                }
            }
            void  make_reg_object(std::string& register_host,const std::string& hostname,std::string& access_host)
            {
                _rclient = std::make_shared<chatroom::Registery>(register_host);
                _rclient->Register(hostname,access_host);
            }
            FriendServer::ptr build()
            {
                if(!_client){
                    Logger_ERROR("语音子模块没有初始化");
                    abort();
                }
                if(!_server){
                    Logger_ERROR("RPC服务子模块没有初始化");
                    abort();
                }
                if(!_rclient){
                    Logger_ERROR("注册服务没有初始化");
                    abort();
                }
                return std::make_shared<FriendServer>(_client,_server,_rclient);
            }
        private:
            std::shared_ptr<brpc::Server> _server;
            chatroom::Registery::ptr _rclient;
    };
}